package com.dynamic.mybatis.core.mock;

import cn.hutool.core.date.DateUtil;
import com.dynamic.mybatis.core.enums.CommandType;
import com.dynamic.mybatis.core.enums.Type;
import com.dynamic.mybatis.core.metadata.MappedStatementMetaField;
import com.dynamic.mybatis.core.toolkit.StringUtils;

import java.util.*;
import java.util.function.Function;

/**
 * @Description
 * @Author xs
 * @Date 2023/4/19 13:14
 */
public interface Mock {
    Map<String,Mock> typeMockMap = new HashMap(){{
        for(Mock typeMock : Mock.TypeMock.values()){
            put(typeMock.type(),typeMock);
        }
    }};
    String type();
    Function function();

    enum TypeMock implements  Mock {
        // new Random().nextInt((max - min) + 1) + min
        TINYINT(Type.StandardType.TINYINT, (field)-> random(field,0,Byte.MAX_VALUE-1)),
        SMALLINT(Type.StandardType.SMALLINT, (field)-> random(field,0,Short.MAX_VALUE-1)),
        INTEGER(Type.StandardType.INTEGER, (field)-> random(field,0,Integer.MAX_VALUE-1)),
        BIGINT(Type.StandardType.BIGINT, (field)-> new Random().nextLong()),
        //Math.random() * (max - min) + min)
        FLOAT(Type.StandardType.FLOAT, (field)-> (float)Math.random() * (Float.MAX_VALUE-1 - 0) + 0),
        DOUBLE(Type.StandardType.DOUBLE, (field)-> Math.random() * (Double.MAX_VALUE-1 - 0) + 0),
        DATE(Type.StandardType.DATE, (field)-> dateFormat(field)),
        TIME(Type.StandardType.TIME, (field)-> dateFormat(field)),
        TIMESTAMP(Type.StandardType.TIMESTAMP, (field)-> dateFormat(field)),
        STING(Type.StandardType.VARCHAR, (field)-> randomString(field.getValidator() != null && field.getValidator().getMaxLength() != null ? field.getValidator().getMaxLength().intValue()/2: 5)),
        UNKNOW(Type.StandardType.NULL,(field)-> "UNKNOW")
        ;
        private Type type;
        private Function<MappedStatementMetaField,Object> function;

        TypeMock(Type type, Function<MappedStatementMetaField,Object> function) {
            this.type = type;
            this.function = function;
        }
        public Type getType() {
            return type;
        }

        public Function function() {
            return function;
        }

        @Override
        public String type() {
            return this.type.getType();
        }
        private static   final  String basesStringRandom = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        private static   final  int basesStringRandomLength = basesStringRandom.length();

        private static int random(int min , int max){
          return   new Random().nextInt((max - min) + 1) + min;
        }

        private static Object random(MappedStatementMetaField field,int min , int max){
            if(field.getValidator() != null){
                if(field.getValidator().getMin() != null){
                    min = field.getValidator().getMin().intValue() > min ? field.getValidator().getMin().intValue() : min;
                }
                if(field.getValidator().getMax() != null && field.getValidator().getMax().intValue() > min){
                    max = field.getValidator().getMax().intValue() < max ? field.getValidator().getMax().intValue() : max;
                }
                if(field.getValidator().isUnsigned()){
                    min = min >= 0 ? min : 0;
                }
            }
            return   new Random().nextInt((max - min) + 1) + min;
        }

        private static Object dateFormat(MappedStatementMetaField field){
            if(field.getValidator() != null && StringUtils.isNotBlank(field.getValidator().getDatePattern())){
                return DateUtil.format(new Date(),field.getValidator().getDatePattern());
            }
            return new  Date();
        }


        public static String randomString(Number maxLength) {
            Random random = new Random();
            maxLength  = maxLength != null ? maxLength : 0;
            //指定字符串长度，拼接字符并toString
            StringBuffer stringBuffer = new StringBuffer();
            for (int i = 0; i < maxLength.intValue(); i++) {
                //获取指定长度的字符串中任意一个字符的索引值
                int number= random.nextInt(basesStringRandomLength);
                //根据索引值获取对应的字符
                char charAt = basesStringRandom.charAt(number);
                stringBuffer.append(charAt);
            }
           return stringBuffer.toString();
        }
    }



    static boolean isPrimitive(String type){
        return  typeMockMap.containsKey(type);
    }


    static   Object getValue(MappedStatementMetaField field){
        if(field != null && field.getDefaultValue() != null){
            return field.getDefaultValue();
        }
        if(typeMockMap.containsKey(field.getType())){
            return typeMockMap.get(field.getType()).function().apply(field);
        }
        return  null;
    }

    static Object mock(MappedStatementMetaField field, CommandType commandType) {
        return mock(field,2,  commandType);
    }

    static Object mock(MappedStatementMetaField field) {
        return mock(field,2,  null);
    }

    static Object mock(MappedStatementMetaField field,int size,CommandType commandType) {
        if(field == null){ return null ;}
        Object result;
        if(Mock.isPrimitive(field.getType())){ //基础类型
            if((field.isAutoincrement() && commandType != CommandType.StandardCommand.INSERT && commandType != CommandType.StandardCommand.SELECT)
             || (!field.isAutoincrement() && commandType != CommandType.StandardCommand.SELECT)
             || (commandType == CommandType.StandardCommand.SELECT) && field.getValidator() != null && field.getValidator().isRequired()){
                result =  Mock.getValue(field);
            }else {
                result = null;
            }
        }else if(Mock.isPrimitive(field.getType()) && Type.StandardType.ARRAY.type.equalsIgnoreCase(field.getGenericType())){//数组并且泛型为基本类型
            result =  new ArrayList<>();
             for(int i = 0 ; i < size ; i++){
                 ((List)result).add(Mock.getValue(field));
             }
        }else if(Type.StandardType.STRUCT.type.equals(field.getType())){//map
            result = new HashMap<>();
            for(MappedStatementMetaField child : field.getChildren()){
                ((Map)result).put(child.getField(),Mock.mock(child,size,commandType));
            }
        }else if(Type.StandardType.ARRAY.type.equalsIgnoreCase(field.getType()) && Type.StandardType.STRUCT.type.equalsIgnoreCase(field.getGenericType())){ //数组并且泛型为map
            result = new ArrayList<>();
            for(int i = 0 ; i < size ; i++){
                Map map =new HashMap();
                for(MappedStatementMetaField child : field.getChildren()){
                    map.put(child.getField(),Mock.mock(child,size,commandType));
                }
                ((List)result).add(map);
            }
        }else {//未知类型
             result = TypeMock.UNKNOW.function.apply(field);
         }
        return  result;
    }
}